#include "widget.h"

#include "ui_widget.h"

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
  ui->setupUi(this);
  setWindowTitle(QString("批量反编译dex文件 by smaller QQ:79288789"));
  setWindowIcon(QIcon(":/img/ico_64.ico"));
  fileCount = finishedCount = 0;

  /* 监视目录 */
  dexPathWatch = new QFileSystemWatcher(this);
  connect(dexPathWatch, &QFileSystemWatcher::directoryChanged, this,
          &Widget::directoryChanged);

  connect(dexPathWatch, &QFileSystemWatcher::fileChanged, this,
          &Widget::fileChanged);
  dexPathWatch->addPath(QCoreApplication::applicationDirPath());
  findBackSmali();
}

Widget::~Widget() {
  if (workPool.count() > 0) {
    for (int i = 0; workPool.count(); i++) {
      workProces *tmp = workPool.at(i);
      delete tmp;
      tmp = NULL;
    }
    workPool.clear();
  }
  if (NULL != dexPathWatch) {
    delete dexPathWatch;
    dexPathWatch = Q_NULLPTR;
  }

  delete ui;
}

void Widget::directoryChanged(const QString &path) {
  Q_UNUSED(path);
  /* 更新dexPath目录 */
  upDexFileList();
  /* 查找backsmali文件列表 */
  findBackSmali();
}

void Widget::fileChanged(const QString &path) {
  qDebug() << "fileChanged" << path;
}

void Widget::onReadData(const QByteArray &data) {
  ui->outDexInfo->append(data.toStdString().c_str());
}

void Widget::onReadError(const QByteArray &data) {
  ui->outDexInfo->append(data.toStdString().c_str());
}

void Widget::on_selectDexPath_clicked() {
  /* 打开保存界面 */
  /* 用户选择需保存的路径 */
  QString sPath = QFileDialog::getExistingDirectory(
      this, QString("选择dex所在目录"),
      QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
      QFileDialog::DontResolveSymlinks);
  if (sPath.isEmpty() == true) {
    savePath.clear();
    return;
  }

  dexPath = sPath;
  ui->dexPath->setText(QDir::toNativeSeparators(sPath));
  dexPathWatch->addPath(dexPath);
}

void Widget::deleteDirectory(const QString &path) {
  QDir dir(path);
  if (!dir.exists()) {
    return;
  }

  dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
  QFileInfoList fileList = dir.entryInfoList();

  foreach (QFileInfo fi, fileList) {
    if (fi.isFile()) {
      fi.dir().remove(fi.fileName());
    } else {
      deleteDirectory(fi.absoluteFilePath());
      dir.rmdir(fi.absoluteFilePath());
    }
  }
}

QStringList Widget::getDirectoryFileList(const QString &path,
                                         const QStringList &filters) {
  QStringList filesList;
  Q_UNUSED(path);
  Q_UNUSED(filters);
  QDir dir(path);
  QFileInfoList fileList;
  do {
    if (!dir.exists())
      break;
    if (filters.isEmpty())
      break;
    dir.setNameFilters(filters);

    fileList = dir.entryInfoList(); /* 获取文件 */

    foreach (QFileInfo fi, fileList) {
      if (fi.isFile()) {
        filesList << fi.filePath();
      } else {
        filesList += getDirectoryFileList(fi.absoluteFilePath(), filters);
      }
    }

  } while (0);

  return filesList;
}

void Widget::on_jdkBtn_clicked() {
  QString sPath, javaBin, jrePath, javaHome;

  do {
    sPath = QFileDialog::getExistingDirectory(
        this, QString("选择jdk所在目录"),
        QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
        QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    if (sPath.isEmpty() == true) {
      jdkPath.clear();
      break;
    }
    // "JAVA_HOME=C:\\Program Files\\Java\\jdk1.8.0_181"
    jdkPath = sPath;
    javaBin = jdkPath + "/bin";
    jrePath = jdkPath + "/jre/bin";

    if (false == isDirExist(javaBin) || false == isDirExist(jrePath)) {
      QMessageBox::information(this, "警告:", "不是有效的jdk目录");
      jdkPath.clear();
      break;
    }

    ui->jdkEdit->setText(QDir::toNativeSeparators(jdkPath));

  } while (0);
}

bool Widget::isDirExist(QString fullPath) {
  QDir dir(fullPath);
  if (dir.exists()) {
    return true;
  }
  return false;
}

void Widget::upDexFileList() {
  QStringList fileList, argList;
  QString outPutPath;

  do {
    if (savePath.isEmpty())
      break;
    if (ui->bSmaliBox->count() != bakSmaliList.size())
      break;
    if (ui->bSmaliBox->count() == 0)
      break;
    argList << "-jar" << bakSmaliList.at(ui->bSmaliBox->currentIndex()) << "-o";
    fileList.clear();
    ui->outDexInfo->append(
        QString("读取文件:\n") +
        getDirectoryFileList(dexPath, QStringList("*.dex")).join("\n"));
    fileList += getDirectoryFileList(dexPath, QStringList("*.dex"));

    fileCount = finishedCount = fileList.count();
    workProces *workTmp = NULL;
    poolListParam.clear();

    if (workPool.count() > 0) {
      for (int i = 0; i < workPool.count(); i++) {
        workTmp = workPool.at(i);
        delete workTmp;
        workTmp = NULL;
      }
      workPool.clear();
    }
    for (int i = 0; i < fileList.count(); i++) {
      if (i == 0) {
        outPutPath = savePath + QString("/class");
      } else {
        outPutPath = savePath + QString("/class%1").arg(QString::number(i + 1));
      }
      argList << outPutPath;
      argList.append(fileList.at(i));
      poolListParam << argList;

      // tasksPool.start(new procTask(this, jdkPath, QString("java"), argList));
      workTmp = new workProces();
      workTmp->setObjectName(QString("workTmp%1").arg(QString::number(i)));
      workPool.append(workTmp);
      connect(workPool.at(i), &workProces::ReadData, this, &Widget::onReadData,
              Qt::QueuedConnection);
      connect(workPool.at(i), &workProces::ReadError, this,
              &Widget::onReadError, Qt::QueuedConnection);
      connect(workPool.at(i), &workProces::finished, this,
              &Widget::runnableFinished, Qt::QueuedConnection);
      connect(this, &Widget::setProcInfo, workPool.at(i),
              &workProces::setRunInfo, Qt::QueuedConnection);
      connect(this, &Widget::doWork, workPool.at(i), &workProces::doMyWork,
              Qt::QueuedConnection);

      argList.removeAt(argList.count() - 1);
      argList.removeAt(argList.count() - 1);
      workTmp = NULL;
    }
    if (workPool.count() != poolListParam.count())
      break;
    QStringList tmp;
    for (int i = 0; i < workPool.count(); i++) {
      tmp.clear();
      tmp = poolListParam.at(i);
      emit setProcInfo(QString("workTmp%1").arg(QString::number(i)), jdkPath,
                       QString("java"), tmp);
    }
  } while (0);
}

void Widget::on_dexBrowerBtn_clicked() {
  /* 打开保存界面 */
  /* 用户选择需保存的路径 */
  QString sPath = QFileDialog::getExistingDirectory(
      this, QString("选择输出目录"),
      QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
      QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
  if (sPath.isEmpty() == true) {
    savePath.clear();
    return;
  }

  savePath = sPath;
  upDexFileList();
  ui->dexOutEdit->setText(QDir::toNativeSeparators(sPath));
}

void Widget::runnableFinished() {
  float proc = 0;
  finishedCount--;

  if (finishedCount == 0) {
    ui->outDexInfo->append("处理完成!");
    ui->progressBar->setValue(100);
  } else {
    proc = (float)(fileCount - finishedCount) / fileCount;
    proc *= 100;
    ui->progressBar->setValue(int(proc));
  }
}

void Widget::on_dex2SmliBtn_clicked() {
  ui->dex2SmliBtn->setEnabled(false);
  ui->progressBar->setMaximum(100);
  ui->progressBar->setValue(0);

  upDexFileList();
  emit doWork();
  ui->dex2SmliBtn->setEnabled(true);
}

void Widget::on_jdkEdit_editingFinished() {
  QString sPath = ui->jdkEdit->text();
  QString javaBin, jrePath;
  do {
    if (sPath.isEmpty() == true) {
      jdkPath.clear();
      break;
    }
    // "JAVA_HOME=C:\\Program Files\\Java\\jdk1.8.0_181"
    jdkPath = sPath;
    javaBin = jdkPath + "/bin";
    jrePath = jdkPath + "/jre/bin";

    if (false == isDirExist(javaBin) || false == isDirExist(jrePath)) {
      QMessageBox::information(this, "警告:", "不是有效的jdk目录");
      jdkPath.clear();
      break;
    }
    ui->jdkEdit->setText(QDir::toNativeSeparators(jdkPath));
  } while (0);
}

void Widget::on_dexPath_editingFinished() {
  QString sPath = ui->dexPath->text();
  if (sPath.isEmpty())
    return;
  dexPath = sPath;
  ui->dexPath->setText(QDir::toNativeSeparators(sPath));
  dexPathWatch->addPath(dexPath);
}

void Widget::on_dexOutEdit_editingFinished() {
  QString sPath = ui->dexOutEdit->text();
  if (sPath.isEmpty())
    return;
  savePath = sPath;
  upDexFileList();
  ui->dexOutEdit->setText(QDir::toNativeSeparators(sPath));
}

void Widget::findBackSmali() {
  QStringList fileList, tmpSmaliList, tmpBakSmaliList, T1, T2;

  fileList += getDirectoryFileList(QCoreApplication::applicationDirPath(),
                                   QStringList("*.jar"));

  tmpSmaliList = fileList.filter("smali");

  tmpBakSmaliList = tmpSmaliList.filter("bak");
  for (int i = 0; i < tmpBakSmaliList.size(); i++) {
    tmpSmaliList.removeOne(tmpBakSmaliList[i]);
  }

  bakSmaliList = tmpBakSmaliList;
  smaliList = tmpSmaliList;

  /* 去除路径 */
  QString tmpBak;
  QFileInfo info;
  T1.clear();

  for (int i = 0; i < tmpBakSmaliList.size(); i++) {
    tmpBak = tmpBakSmaliList.at(i);
    info.setFile(tmpBak);
    tmpBak = info.fileName();
    T1.append(tmpBak);
  }
  T2.clear();
  for (int i = 0; i < tmpSmaliList.size(); i++) {
    tmpBak = tmpSmaliList.at(i);
    info.setFile(tmpBak);
    tmpBak = info.fileName();
    T2.append(tmpBak);
  }

  QString bSm, sm;
  if (ui->bSmaliBox->count() != 0) {
    bSm = ui->bSmaliBox->currentText();
  }

  ui->bSmaliBox->clear();
  ui->bSmaliBox->addItems(T1);

  if (-1 != ui->bSmaliBox->findText(bSm)) {
    ui->bSmaliBox->setCurrentIndex(ui->bSmaliBox->findText(bSm));
  }
}
